package com.ghck.server.service.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ghck.server.controller.events.RedisSyncEvent;
import com.ghck.server.dao.DepartmentDictMapper;
import com.ghck.server.model.DepartmentDict;
import com.ghck.server.model.query.DepartmentDictQuery;
import com.ghck.server.service.DepartmentDictService;
import com.ghck.server.utils.IntegerUtil;
import com.ghck.server.utils.RedisKeyUtil;
import com.ghck.server.utils.SpringContextUtil;

/**
 * 科室  <br>
 * dict_department <br>
 * v1.0 2016-05-01
 */
@Service
@Transactional
public class DepartmentDictServiceImpl implements DepartmentDictService {

	private static final Logger logger = LoggerFactory.getLogger(DepartmentDictServiceImpl.class);

	@Autowired
	private RedisTemplate<String, Object> template;

	@Autowired
	private DepartmentDictMapper departmentDictMapper;

	/**
	 *根据ID删除 科室
	 */
	@Override
	public Integer deleteDepartmentDictById(Integer id){
		return departmentDictMapper.deleteById(id);
	}

	/**
	 *新增 科室
	 */
	@Override
	@Transactional
	public Integer batchInsertDepartmentDict(List<? extends DepartmentDict> departmentDicts){
		Integer count = departmentDictMapper.batchInsert(departmentDicts);
		return count;
	}
	/**
	 *新增 科室
	 */
	@Override
	@Transactional
	public Integer insertDepartmentDict(DepartmentDict domain){
		departmentDictMapper.insert(domain);

		Integer id = domain.getId();

		if(IntegerUtil.isPositiveInteger(id)){
			RedisSyncEvent event = new RedisSyncEvent(id, RedisSyncEvent.DEPARTMENT);
			SpringContextUtil.getApplicationContext().publishEvent(event);
		}

		return id;
	}

	/**
	 *更新 科室
	 */
	@Override
	@Transactional
	public Integer updateDepartmentDict(DepartmentDict domain){
		departmentDictMapper.update(domain);
		Integer id = domain.getId();
		if(IntegerUtil.isPositiveInteger(id)){
			RedisSyncEvent event = new RedisSyncEvent(id, RedisSyncEvent.DEPARTMENT);
			SpringContextUtil.getApplicationContext().publishEvent(event);
		}
		return id;
	}

	/**
	 *根据ID查询 科室
	 */
	public DepartmentDict findByIdWithCache(Integer id){
		String key = RedisKeyUtil.departmentHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String hashKey = RedisKeyUtil.domainIdKey(id);
		Object resutl = template.opsForHash().get(key, hashKey);
		if(resutl instanceof DepartmentDict){
			return (DepartmentDict) resutl;
		}
		return null;
	}

	@Override
	public DepartmentDict findById(Integer id) {
		return departmentDictMapper.findById(id);
	}

	public DepartmentDict findDepartmentDictByIdWithCache(Integer id){
		String key = RedisKeyUtil.departmentHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String hashKey = RedisKeyUtil.domainIdKey(id);
		Object object = template.opsForHash().get(key, hashKey);
		if(object instanceof DepartmentDict){
			return (DepartmentDict) object;
		}
		return null;
	}

	/**
	 *通过query 查询 科室
	 */
	public List<DepartmentDict> findDepartmentDictByQuery(DepartmentDictQuery query){
		query.dealWith();
		List<DepartmentDict> result = departmentDictMapper.findByQuery(query);
		if(CollectionUtils.isNotEmpty(result)) {
			Collections.sort(result);
			for (DepartmentDict departmentDict : result) {
				departmentDict.dealWith();
			}
		}
		return result;
	}	

	/**
	 *通过query count总条数
	 */
	public Integer countDepartmentDictByQuery(DepartmentDictQuery query){
		query.dealWith();
		Integer result = departmentDictMapper.countByQuery(query);
		return result;
	}

	/**
	 * 通过ids查询
	 */
	public List<DepartmentDict> findDepartmentDictByIds(List<Integer> ids){
		List<DepartmentDict> result = departmentDictMapper.findByIds(ids);
		if(CollectionUtils.isNotEmpty(result)) {
			for (DepartmentDict departmentDict : result) {
				departmentDict.dealWith();
			}
		}
		return result;
	}

	/**
	 *根据name查询 身体部位
	 */
	public DepartmentDict findByName(String name){
		DepartmentDict result = departmentDictMapper.findByName(name);
		if(result!=null){
			result.dealWith();
		}
		return result;
	}

	/**
	 *获取所有字典 身体部位
	 */
	public List<DepartmentDict> findAll(){
		List<DepartmentDict> result = departmentDictMapper.findAll();
		if(CollectionUtils.isNotEmpty(result)) {
			for (DepartmentDict departmentDict : result) {
				departmentDict.dealWith();
			}
		}
		return result;
	}

	@Override
	public List<DepartmentDict> findAllWithCache() {
		String hashKey = RedisKeyUtil.departmentHashKey();
		if(!template.hasKey(hashKey)){
			syncInRedis(true);
		}

		List<Object> values = template.opsForHash().values(hashKey);
		List<DepartmentDict> result = new ArrayList<DepartmentDict>();
		if (CollectionUtils.isNotEmpty(values)) {
			for (Object obj : values) {
				if(obj instanceof DepartmentDict){
					result.add((DepartmentDict) obj);
				}
			}
		}
		return result;
	}

	@Override
	public List<DepartmentDict> findChildrenByParentId(Integer parentId) {
		List<DepartmentDict> result = new ArrayList<DepartmentDict>();
		String key = RedisKeyUtil.departmentHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String parentKey = RedisKeyUtil.parentIdMapDepartmentChildren();

		List<String> hashKeys = new ArrayList<String>();

		String hashKey = RedisKeyUtil.domainIdKey(parentId);

		HashOperations<String, String, List<Integer>> hashOperations = template.opsForHash();
		List<Integer> idList = hashOperations.get(parentKey, hashKey);

		if (CollectionUtils.isNotEmpty(idList)) {
			for (Integer id : idList) {
				String hashKey1 = RedisKeyUtil.domainIdKey(id);
				hashKeys.add(hashKey1);
			}
			if (CollectionUtils.isNotEmpty(hashKeys)) {
				HashOperations<String, String, DepartmentDict> hashOperations1 = template.opsForHash();
				List<DepartmentDict> list = hashOperations1.multiGet(key, hashKeys);
				if (CollectionUtils.isNotEmpty(list)) {
					for (DepartmentDict departmentDict : list) {
						result.add(departmentDict);
					}
				}
			}
		}
		return result;
	}

	@Override
	public void syncInRedis(boolean force){
		String key = RedisKeyUtil.departmentHashKey();
		if(force || (!template.hasKey(key) )){
			List<DepartmentDict> result = findAll();
			if (CollectionUtils.isNotEmpty(result)) {
				Map<String, DepartmentDict> map = new HashMap<String, DepartmentDict>();
				Map<Integer, List<Integer>> parentList= new HashMap<Integer, List<Integer>>();
				for (DepartmentDict departmentDict : result) {
					String hashKey = RedisKeyUtil.domainIdKey(departmentDict.getId());
					map.put(hashKey, departmentDict);
					Integer parentId = departmentDict.getParentId();  
					if(!parentList.containsKey(parentId)){
						parentList.put(parentId, new ArrayList<Integer>());
					}
					parentList.get(parentId).add(departmentDict.getId());
				}
				template.delete(key);
				template.opsForHash().putAll(key, map);
//				template.expire(key, 7, TimeUnit.DAYS);

				if(!parentList.isEmpty()){
					String parentKey = RedisKeyUtil.parentIdMapDepartmentChildren();
					template.delete(parentKey);

					Map<String, List<Integer>> tempMap = new HashMap<String, List<Integer>>();
					for (Entry<Integer, List<Integer>> entry : parentList.entrySet()) {
						Integer parentId = entry.getKey();
						String parentHashKey = RedisKeyUtil.domainIdKey(parentId);
						List<Integer> values = entry.getValue();
						tempMap.put(parentHashKey, values);
					}
					template.opsForHash().putAll(parentKey, tempMap);
//					template.expire(parentKey, 8, TimeUnit.DAYS);
				}
			}
		}
	}

	@Override
	public void syncSingletonRedis(Integer departmentId) {
		String key = RedisKeyUtil.departmentHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}else{
			DepartmentDict departmentDict = departmentDictMapper.findById(departmentId);
			String hashKey = RedisKeyUtil.domainIdKey(departmentId);
			if(departmentDict.getInUsed()==1){
				template.opsForHash().put(key, hashKey, departmentDict);
			}else{
				template.opsForHash().delete(key, hashKey);
			}


			//加载父节点对应的子儿子集合
			Integer parentId = departmentDict.getParentId();
			String parentKey = RedisKeyUtil.parentIdMapDepartmentChildren();
			hashKey = RedisKeyUtil.domainIdKey(parentId);
			if(template.opsForHash().hasKey(parentKey, hashKey)){
				Object list = template.opsForHash().get(parentKey, hashKey);
				if(list instanceof List){
					boolean find =false;
					Object findObject = null;
					for (Object item : (List)list) {
						if(item instanceof Integer){
							if(departmentId.intValue() == (Integer)item){
								find = true;
								findObject = item;
								break;
							}
						}
					}
					if(!find){
						if(departmentDict.getInUsed()==1){
							((List)list).add(departmentId);
							template.opsForHash().put(parentKey, hashKey,list);
						}
					}else{
						if(departmentDict.getInUsed()==0){
							((List)list).remove(findObject);
							template.opsForHash().put(parentKey, hashKey,list);
						}
					}
				}
			}else if(departmentDict.getInUsed()==1){
				List<Integer> list = new ArrayList<Integer>();
				list.add(departmentId);
				template.opsForHash().put(parentKey, hashKey,list);
			}

		}
	}
}	